﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Reflection;

namespace Tools {
	public partial class wndMain : Form {
		public Image CurrentAsset { get; set; }
		public Image CurrentMaskAsset { get; set; }
		public int Zoom { get; set; }

		public MouseButtons IsMouseDown { get; set; }
		public bool Selection { get; set; }
		public Point StartPoint { get; set; }
		public Point EndPoint { get; set; }
		public Point MovePoint { get; set; }

		public string ActiveFile { get; set; }
		public bool ActiveFileSaved { get; set; }

		// ----------
		// Constructor

		public wndMain() {
			InitializeComponent();

			Globals.SetDoubleBuffered( pnlCanvasHolder );
			Globals.SetDoubleBuffered( pbCanvas );

			// ----------

			Globals.Extensions = new Dictionary<string,int>();
			Globals.Extensions[".png"] = 2;
			Globals.Extensions[".jpg"] = 2;
			Globals.Extensions[".jpeg"] = 2;
			Globals.Extensions[".gif"] = 2;
			Globals.Extensions[".mp3"] = 3;
			Globals.Extensions[".wav"] = 3;
			Globals.Extensions[".wma"] = 3;
			Globals.Extensions[".txt"] = 4;
			Globals.Extensions[".cfg"] = 4;
			Globals.Extensions[".ini"] = 4;
			Globals.Extensions[".xml"] = 4;

			Globals.AssetsPath = Path.GetFullPath( "..\\..\\..\\Spacer\\SpacerContent\\" );
			txtAssetsPath.Text = Globals.AssetsPath;

			Globals.StartSnapSize = 1;
			Globals.ExpandSnapSize = 1;

			Zoom = 1;

			propertyGrid1.SelectedObject = new Types.SpriteCfg();
			ActiveFileSaved = true;
		}

		// ----------
		// Hooks

		private void wndMain_FormClosing( object sender, FormClosingEventArgs e ) {
			if( !ActiveFileSaved ) {
				DialogResult res = MessageBox.Show( "Save '" + ((Types.SpriteCfg)propertyGrid1.SelectedObject).Name + "' before exitting?", "Save", MessageBoxButtons.YesNoCancel );
				if( res == DialogResult.Yes ) {
					saveToolStripMenuItem_Click( null, null );
				} else if( res == DialogResult.Cancel ) {
					e.Cancel = true;
				}
			}
		}

		private void wndMain_Resize( object sender, EventArgs e ) {
			HandleResize();
		}

		private void pbCanvas_Paint( object sender, PaintEventArgs e ) {
			int cw = (int)( (float)pbCanvas.Width / (float)Zoom + 1 ) * Zoom;
			int ch = (int)( (float)pbCanvas.Height / (float)Zoom + 1 ) * Zoom;
			int fix = 32 * Zoom;
			
			// Graphics settings
			e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
			e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
			
			// Draw Background
			System.Drawing.Imaging.ImageAttributes attrs = new System.Drawing.Imaging.ImageAttributes();
			attrs.SetWrapMode( System.Drawing.Drawing2D.WrapMode.Tile );
				
			e.Graphics.DrawImage( Properties.Resources.background, new Rectangle(-fix,-fix,cw+fix,ch+fix), 0, 0, (cw+fix)/Zoom, (ch+fix)/Zoom, GraphicsUnit.Pixel, attrs );

			Image asset = null;
			if( !Globals.ShowMask )
				asset = CurrentAsset;
			else
				asset = CurrentMaskAsset;

			if( asset != null ) {
				int aw = asset.Width * Zoom;
				int ah = asset.Height * Zoom;

				// Draw Asset
				e.Graphics.DrawImage( asset, 0, 0, aw, ah );

				// Asset Outline
				if( Globals.ShowOutline ) {
					Pen p = new Pen( Color.FromArgb(200,255,100,100) );
					p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
				
					e.Graphics.DrawLine( p, aw+1, 0, aw+1, ah+1 );
					e.Graphics.DrawLine( p, 0, ah+1, aw+1, ah+1 );
				}
			}
			
			// Draw Grid
			if( Globals.PixelGrid && Zoom > 2 ) {
				for(int y=-1;y<=pbCanvas.Height;y+=Zoom)
					e.Graphics.FillRectangle( new SolidBrush(Color.FromArgb(100,85,85,85)), 0, (y==-1?0:y), pbCanvas.Width, (y==-1?1:2) );
				for(int x=-1;x<=pbCanvas.Width;x+=Zoom)
					e.Graphics.FillRectangle( new SolidBrush(Color.FromArgb(100,85,85,85)), (x==-1?0:x), 0, (x==-1?1:2), pbCanvas.Height );
			}

			// Draw selection
			if( Selection ) {
				Point start = new Point(
					(StartPoint.X < EndPoint.X ? StartPoint.X : EndPoint.X),
					(StartPoint.Y < EndPoint.Y ? StartPoint.Y : EndPoint.Y)
				);

				Point end = new Point(
					(StartPoint.X > EndPoint.X ? StartPoint.X : EndPoint.X),
					(StartPoint.Y > EndPoint.Y ? StartPoint.Y : EndPoint.Y)
				);
				
				int x = start.X * Zoom;
				int y = start.Y * Zoom;
				int w = (end.X - start.X) * Zoom;
				int h = (end.Y - start.Y) * Zoom;

				e.Graphics.FillRectangle( new SolidBrush(Color.FromArgb(100,50,220,50)), x, y, w, h );

				e.Graphics.DrawLine( new Pen(Color.FromArgb(255,50,255,50)), x, y+1, x+w, y+1 );
				e.Graphics.DrawLine( new Pen(Color.FromArgb(255,50,255,50)), x, y+h, x+w, y+h );
				e.Graphics.DrawLine( new Pen(Color.FromArgb(255,50,255,50)), x+1, y+1, x+1, y+h-1 );
				e.Graphics.DrawLine( new Pen(Color.FromArgb(255,50,255,50)), x+w, y+1, x+w, y+h-1 );
				
				e.Graphics.DrawLine( new Pen(Color.FromArgb(200,100,100,255)), x+(w/2)-3, y+(h/2)-3, x+(w/2)+3, y+(h/2)+3 );
				e.Graphics.DrawLine( new Pen(Color.FromArgb(200,100,100,255)), x+(w/2)-3, y+(h/2)+3, x+(w/2)+3, y+(h/2)-3 );
				
				e.Graphics.DrawLine( new Pen(Color.FromArgb(200,255,100,100)), x-3, y-3, x+3, y+3 );
				e.Graphics.DrawLine( new Pen(Color.FromArgb(200,255,100,100)), x-3, y+3, x+3, y-3 );
			}
		}

		private void ddbZoom_DropDownItemClicked( object sender, ToolStripItemClickedEventArgs e ) {
			ddbZoom.Text = e.ClickedItem.Text;

			Zoom = Int32.Parse( e.ClickedItem.Text.Substring(0,e.ClickedItem.Text.Length-1) ) / 100;
			
			HandleResize();
			pbCanvas.Refresh();
		}

		private void pbCanvas_MouseLeave( object sender, EventArgs e ) {
			lblMousePos.Text = "X: -   Y: -";
		}

		private void pbCanvas_MouseDown( object sender, MouseEventArgs e ) {
			if( IsMouseDown != MouseButtons.None )
				return;

			if( e.Button == MouseButtons.Left ) {
				Point pos = e.Location;

				//pos.X = (int)( Math.Floor( (float)pos.X / (float)Globals.StartSnapSize + 0.5f ) * (float)Globals.StartSnapSize);
				//pos.Y = (int)( Math.Floor( (float)pos.Y / (float)Globals.StartSnapSize + 0.5f ) * (float)Globals.StartSnapSize);

				IsMouseDown = MouseButtons.Left;
				pbCanvas.Capture = true;
				timer1.Enabled = true;
				
				if( Zoom > 1 ) {
					StartPoint = new Point(
						(int)((float)pos.X + ((float)Zoom*0.5f)) / Zoom,
						(int)((float)pos.Y + ((float)Zoom*0.5f)) / Zoom
					);
					EndPoint = StartPoint;
				} else {
					StartPoint = new Point(
						pos.X,
						pos.Y
					);
					EndPoint = StartPoint;
				}

				// Adjust for snap sizes
				StartPoint = new Point(
					(int)( Math.Floor( (float)StartPoint.X / (float)Globals.StartSnapSize + 0.5f ) * (float)Globals.StartSnapSize),
					(int)( Math.Floor( (float)StartPoint.Y / (float)Globals.StartSnapSize + 0.5f ) * (float)Globals.StartSnapSize)
				);

				Selection = false;
				lblCurrentRegion.Text = "X: -   Y: -   W: -   H: -";
			} else if( e.Button == MouseButtons.Middle ) {
				IsMouseDown = MouseButtons.Middle;
				MovePoint = e.Location;
			}

			pbCanvas.Refresh();
		}

		private void pbCanvas_MouseMove( object sender, MouseEventArgs e ) {
			Point pos = e.Location;
			pos.X = (pos.X < 0 ? 0 : (pos.X > pbCanvas.Width ? pbCanvas.Width : pos.X));
			pos.Y = (pos.Y < 0 ? 0 : (pos.Y > pbCanvas.Height ? pbCanvas.Height : pos.Y));

			lblMousePos.Text = "X: "+ (pos.X / Zoom) +"   Y: "+ (pos.Y / Zoom);
			
			if( IsMouseDown == MouseButtons.Left ) {
				if( Zoom > 1 ) {
					EndPoint = new Point(
						(int)((float)pos.X + ((float)Zoom*0.5f)) / Zoom,
						(int)((float)pos.Y + ((float)Zoom*0.5f)) / Zoom
					);
				} else {
					EndPoint = new Point(
						pos.X,
						pos.Y
					);
				}

				// Adjust for snap sizes
				EndPoint = new Point(
					StartPoint.X + (int)( Math.Floor( (float)(EndPoint.X-StartPoint.X) / (float)Globals.ExpandSnapSize + 0.5f ) * (float)Globals.ExpandSnapSize),
					StartPoint.Y + (int)( Math.Floor( (float)(EndPoint.Y-StartPoint.Y) / (float)Globals.ExpandSnapSize + 0.5f ) * (float)Globals.ExpandSnapSize)
				);

				if( StartPoint.X == EndPoint.X || StartPoint.Y == EndPoint.Y ) {
					Selection = false;
					lblCurrentRegion.Text = "X: -   Y: -   W: -   H: -";
				} else {
					Point start = new Point(
						(StartPoint.X < EndPoint.X ? StartPoint.X : EndPoint.X),
						(StartPoint.Y < EndPoint.Y ? StartPoint.Y : EndPoint.Y)
					);

					Point end = new Point(
						(StartPoint.X > EndPoint.X ? StartPoint.X : EndPoint.X),
						(StartPoint.Y > EndPoint.Y ? StartPoint.Y : EndPoint.Y)
					);

					Selection = true;
					lblCurrentRegion.Text = "X: "+ start.X +"   Y: "+ start.Y +"   W: "+ (int)Math.Abs(end.X-start.X) +"   H: "+ (int)Math.Abs(end.Y-start.Y);
				}
			} else if( IsMouseDown == MouseButtons.Middle ) {
				Point delta = new Point( e.Location.X - MovePoint.X, e.Location.Y - MovePoint.Y );

				pnlCanvasHolder.HorizontalScroll.Value = Clamp( pnlCanvasHolder.HorizontalScroll.Value-delta.X, pnlCanvasHolder.HorizontalScroll.Minimum, pnlCanvasHolder.HorizontalScroll.Maximum );
				pnlCanvasHolder.VerticalScroll.Value = Clamp( pnlCanvasHolder.VerticalScroll.Value-delta.Y, pnlCanvasHolder.VerticalScroll.Minimum, pnlCanvasHolder.VerticalScroll.Maximum );
				
				pnlCanvasHolder.PerformLayout();
				pnlCanvasHolder.Refresh();
			}
			
			pbCanvas.Refresh();
		}

		private void pbCanvas_MouseUp( object sender, MouseEventArgs e ) {
			if( e.Button == MouseButtons.Left && IsMouseDown == MouseButtons.Left ) {
				Point pos = e.Location;
				pos.X = (pos.X < 0 ? 0 : (pos.X > pbCanvas.Width ? pbCanvas.Width : pos.X));
				pos.Y = (pos.Y < 0 ? 0 : (pos.Y > pbCanvas.Height ? pbCanvas.Height : pos.Y));
			
				pbCanvas.Capture = false;
				timer1.Enabled = false;

				if( Zoom > 1 ) {
					EndPoint = new Point(
						(int)((float)pos.X + ((float)Zoom*0.5f)) / Zoom,
						(int)((float)pos.Y + ((float)Zoom*0.5f)) / Zoom
					);
				} else {
					EndPoint = new Point(
						pos.X,
						pos.Y
					);
				}

				// Adjust for snap sizes
				EndPoint = new Point(
					StartPoint.X + (int)( Math.Floor( (float)(EndPoint.X-StartPoint.X) / (float)Globals.ExpandSnapSize + 0.5f ) * (float)Globals.ExpandSnapSize),
					StartPoint.Y + (int)( Math.Floor( (float)(EndPoint.Y-StartPoint.Y) / (float)Globals.ExpandSnapSize + 0.5f ) * (float)Globals.ExpandSnapSize)
				);

				if( StartPoint.X == EndPoint.X || StartPoint.Y == EndPoint.Y ) {
					Selection = false;
					lblCurrentRegion.Text = "X: -   Y: -   W: -   H: -";
				} else {
					Point start = new Point(
						(StartPoint.X < EndPoint.X ? StartPoint.X : EndPoint.X),
						(StartPoint.Y < EndPoint.Y ? StartPoint.Y : EndPoint.Y)
					);

					Point end = new Point(
						(StartPoint.X > EndPoint.X ? StartPoint.X : EndPoint.X),
						(StartPoint.Y > EndPoint.Y ? StartPoint.Y : EndPoint.Y)
					);

					Selection = true;
					lblCurrentRegion.Text = "X: "+ start.X +"   Y: "+ start.Y +"   W: "+ (int)Math.Abs(end.X-start.X) +"   H: "+ (int)Math.Abs(end.Y-start.Y);
				}

			}

			IsMouseDown = MouseButtons.None;

			pbCanvas.Refresh();
		}

		private void timer1_Tick( object sender, EventArgs e ) {
			// Do scrolling if off an edge
			int amt = 5 * (Zoom+1 / 2);

			Point pos = Cursor.Position;
			Point tl = pnlCanvasHolder.PointToScreen( pnlCanvasHolder.ClientRectangle.Location );
			Point br = pnlCanvasHolder.PointToScreen( new Point(pnlCanvasHolder.ClientRectangle.Width,pnlCanvasHolder.ClientRectangle.Height) );
			
			if( pos.X < tl.X )
				pnlCanvasHolder.HorizontalScroll.Value = (pnlCanvasHolder.HorizontalScroll.Value-amt > pnlCanvasHolder.HorizontalScroll.Minimum ? pnlCanvasHolder.HorizontalScroll.Value-amt : pnlCanvasHolder.HorizontalScroll.Minimum);
			
			if( pos.X > br.X )
				pnlCanvasHolder.HorizontalScroll.Value = (pnlCanvasHolder.HorizontalScroll.Value+amt < pnlCanvasHolder.HorizontalScroll.Maximum ? pnlCanvasHolder.HorizontalScroll.Value+amt : pnlCanvasHolder.HorizontalScroll.Maximum);
			
			if( pos.Y < tl.Y )
				pnlCanvasHolder.VerticalScroll.Value = (pnlCanvasHolder.VerticalScroll.Value-amt > pnlCanvasHolder.VerticalScroll.Minimum ? pnlCanvasHolder.VerticalScroll.Value-amt : pnlCanvasHolder.VerticalScroll.Minimum);
			
			if( pos.Y > br.Y )
				pnlCanvasHolder.VerticalScroll.Value = (pnlCanvasHolder.VerticalScroll.Value+amt < pnlCanvasHolder.VerticalScroll.Maximum ? pnlCanvasHolder.VerticalScroll.Value+amt : pnlCanvasHolder.VerticalScroll.Maximum);
			
		}

		// ----------
		// Menu

		private void newToolStripMenuItem_Click( object sender, EventArgs e ) {
			if( !ActiveFileSaved ) {
				DialogResult res = MessageBox.Show( "Save '" + ((Types.SpriteCfg)propertyGrid1.SelectedObject).Name + "' before exitting?", "Save", MessageBoxButtons.YesNoCancel );
				if( res == DialogResult.Yes ) {
					saveToolStripMenuItem_Click( null, null );
				} else if( res == DialogResult.Cancel ) {
					return;
				}
			}

			propertyGrid1.SelectedObject = new Types.SpriteCfg();
			propertyGrid1.Refresh();

			foreach(GridItem item in GetAllGridEntries(propertyGrid1)) {
				if( item.GridItemType != GridItemType.Category )
					propertyGrid1_PropertyValueChanged( propertyGrid1, new PropertyValueChangedEventArgs(item,null) );
			}

			ActiveFile = "";
			ActiveFileSaved = true;
		}

		private void openToolStripMenuItem_Click( object sender, EventArgs e ) {
			if( !ActiveFileSaved ) {
				DialogResult res = MessageBox.Show( "Save '" + ((Types.SpriteCfg)propertyGrid1.SelectedObject).Name + "' before exitting?", "Save", MessageBoxButtons.YesNoCancel );
				if( res == DialogResult.Yes ) {
					saveToolStripMenuItem_Click( null, null );
				} else if( res == DialogResult.Cancel ) {
					return;
				}
			}

			OpenFileDialog ofd = new OpenFileDialog();
			ofd.CheckFileExists = true;
			ofd.AddExtension = true;
			ofd.DefaultExt = ".xml";
			ofd.Filter = "Xml Configuration Files (*.xml)|*.xml|All files (*.*)|*.*";
			ofd.InitialDirectory = Globals.AssetsPath;
			ofd.Title = "Open Sprite Configuration...";

			if( ofd.ShowDialog() == DialogResult.OK ) {
				ActiveFile = ofd.FileName;
			} else {
				newToolStripMenuItem_Click( null, null );
				return;
			}

			propertyGrid1.SelectedObject = null;

			XmlReader reader = null;
			try {
				reader = XmlReader.Create( ActiveFile );
				XmlSerializer serializer = new XmlSerializer( typeof(Types.SpriteCfg) );
				propertyGrid1.SelectedObject = serializer.Deserialize( reader );

				reader.Close();
			} catch( Exception x ) {
				if( reader != null )
					reader.Close();

				MessageBox.Show( x.Message, "Could not open file!" );

				newToolStripMenuItem_Click( null, null );
			}

			if( propertyGrid1.SelectedObject == null ) {
				newToolStripMenuItem_Click( null, null );
			}

			foreach(GridItem item in GetAllGridEntries(propertyGrid1)) {
				if( item.GridItemType != GridItemType.Category )
					propertyGrid1_PropertyValueChanged( propertyGrid1, new PropertyValueChangedEventArgs(item,null) );
			}
			
			ActiveFileSaved = true;
		}

		private void saveToolStripMenuItem_Click( object sender, EventArgs e ) {
			if( propertyGrid1.SelectedObject == null )
				return;

			if( ActiveFile == null || ActiveFile.Length == 0 ) {
				SaveFileDialog sfd = new SaveFileDialog();
				sfd.AddExtension = true;
				sfd.DefaultExt = ".xml";
				sfd.FileName = ((Types.SpriteCfg)propertyGrid1.SelectedObject).Name + ".xml";
				sfd.Filter = "Xml Configuration Files (*.xml)|*.xml|All files (*.*)|*.*";
				sfd.InitialDirectory = Globals.AssetsPath;
				sfd.OverwritePrompt = true;
				sfd.Title = "Save " + ((Types.SpriteCfg)propertyGrid1.SelectedObject).Name + "...";

				if( sfd.ShowDialog() == DialogResult.OK ) {
					ActiveFile = sfd.FileName;
				} else {
					return;
				}
			}

			if( ActiveFile != null && ActiveFile.Length != 0 ) {
				XmlWriter writer = null;

				try {
					XmlWriterSettings settings = new XmlWriterSettings();
					settings.Indent = true;
					settings.IndentChars = "\t";
					settings.NewLineChars = "\r\n";
					settings.NewLineHandling = NewLineHandling.Replace;
					settings.NewLineOnAttributes = true;

					writer = XmlWriter.Create( ActiveFile, settings );
					XmlSerializer serializer = new XmlSerializer( propertyGrid1.SelectedObject.GetType() );
					serializer.Serialize( writer, propertyGrid1.SelectedObject );

					writer.Close();

					ActiveFileSaved = true;
				} catch( Exception x ) {
					if( writer != null )
						writer.Close();
					MessageBox.Show( x.Message, "Could not save file!" );
				}
			}
		}

		private void saveAsToolStripMenuItem_Click( object sender, EventArgs e ) {
			if( propertyGrid1.SelectedObject == null )
				return;
			
			string temp = ActiveFile;
			ActiveFile = null;
			
			saveToolStripMenuItem_Click( null, null );

			if( ActiveFile == null || ActiveFile.Length == 0 ) {
				ActiveFile = temp;
			}
		}
		
		private void showMaskToolStripMenuItem_CheckedChanged( object sender, EventArgs e ) {
			Globals.ShowMask = (sender == showMaskToolStripMenuItem ? showMaskToolStripMenuItem.Checked : cbShowMask.Checked);

			showMaskToolStripMenuItem.Checked = Globals.ShowMask;
			cbShowMask.Checked = Globals.ShowMask;

			HandleResize();
			pbCanvas.Refresh();
		}

		private void showOutlineToolStripMenuItem_CheckedChanged( object sender, EventArgs e ) {
			Globals.ShowOutline = (sender == showOutlineToolStripMenuItem ? showOutlineToolStripMenuItem.Checked : cbShowOutline.Checked);

			showOutlineToolStripMenuItem.Checked = Globals.ShowOutline;
			cbShowOutline.Checked = Globals.ShowOutline;

			HandleResize();
			pbCanvas.Refresh();
		}

		private void showPixelGridToolStripMenuItem_CheckedChanged( object sender, EventArgs e ) {
			Globals.PixelGrid = (sender == showPixelGridToolStripMenuItem ? showPixelGridToolStripMenuItem.Checked : cbShowPixelGrid.Checked);

			showPixelGridToolStripMenuItem.Checked = Globals.PixelGrid;
			cbShowPixelGrid.Checked = Globals.PixelGrid;

			HandleResize();
			pbCanvas.Refresh();
		}

		private void zoomInToolStripMenuItem_Click( object sender, EventArgs e ) {
			Zoom = Zoom * 2;

			ddbZoom.Text = (Zoom * 100) + "%";
			
			HandleResize();
			pbCanvas.Refresh();
		}

		private void zoomOutToolStripMenuItem_Click( object sender, EventArgs e ) {
			Zoom = Zoom / 2;
			if( Zoom < 1 )
				Zoom = 1;

			ddbZoom.Text = (Zoom * 100) + "%";
			
			HandleResize();
			pbCanvas.Refresh();
		}

		// ----------
		// Context Menu

		private void contextMenuStrip1_Opening( object sender, CancelEventArgs e ) {
			testToolStripMenuItem.Text = (Selection ? "Region selected - Chose action below..." : "No region selected!");
			applySizeToolStripMenuItem.Enabled = Selection;
			applyCenterToolStripMenuItem.Enabled = Selection;
			applyRegionToolStripMenuItem.Enabled = Selection;
			addFrameToolStripMenuItem.Enabled = Selection;
			addFrameIdleSequenceToolStripMenuItem.Enabled = Selection;

			while( contextMenuStrip1.Items.Count > 9 )
				contextMenuStrip1.Items.RemoveAt( 9 );

			if( propertyGrid1.SelectedObject != null ) {
				if( ((Types.SpriteCfg)propertyGrid1.SelectedObject).Frames.Count == 0 ) {
					ToolStripMenuItem item = new ToolStripMenuItem( "No frames in config" );
					item.Enabled = false;
					contextMenuStrip1.Items.Add( item );
				} else {
					for(int i=0;i<((Types.SpriteCfg)propertyGrid1.SelectedObject).Frames.Count;i++) {
						ToolStripMenuItem item = new ToolStripMenuItem( "Replace frame "+i );
						item.Click += new EventHandler( replaceFrameToolStripMenuItem_Click );
						item.Tag = i;
						contextMenuStrip1.Items.Add( item );
					}
				}
			} else {
				ToolStripMenuItem item = new ToolStripMenuItem( "No frames in config" );
				item.Enabled = false;
				contextMenuStrip1.Items.Add( item );
			}
		}

		private void applySizeToolStripMenuItem_Click( object sender, EventArgs e ) {
			Types.SpriteCfg cfg = (Types.SpriteCfg)propertyGrid1.SelectedObject;
			cfg.Size = new Vector2(
				Math.Abs( (EndPoint.X - StartPoint.X) ),
				Math.Abs( (EndPoint.Y - StartPoint.Y) )
			);
			
			ActiveFileSaved = false;
			propertyGrid1.Refresh();
		}

		private void applyCenterToolStripMenuItem_Click( object sender, EventArgs e ) {
			Types.SpriteCfg cfg = (Types.SpriteCfg)propertyGrid1.SelectedObject;
			cfg.Center = new Vector2(
				Math.Abs( EndPoint.X - StartPoint.X ) * 0.5f,
				Math.Abs( EndPoint.Y - StartPoint.Y ) * 0.5f
			);
			
			ActiveFileSaved = false;
			propertyGrid1.Refresh();
		}

		private void applyRegionToolStripMenuItem_Click( object sender, EventArgs e ) {
			Types.SpriteCfg cfg = (Types.SpriteCfg)propertyGrid1.SelectedObject;

			cfg.Size = new Vector2(
				Math.Abs( (EndPoint.X - StartPoint.X) ),
				Math.Abs( (EndPoint.Y - StartPoint.Y) )
			);

			cfg.Center = new Vector2(
				Math.Abs( EndPoint.X - StartPoint.X ) * 0.5f,
				Math.Abs( EndPoint.Y - StartPoint.Y ) * 0.5f
			);
			
			ActiveFileSaved = false;
			propertyGrid1.Refresh();
		}

		private void addFrameToolStripMenuItem_Click( object sender, EventArgs e ) {
			Types.SpriteCfg cfg = (Types.SpriteCfg)propertyGrid1.SelectedObject;

			cfg.Frames.Add( new Vector2(
				Math.Min( StartPoint.X, EndPoint.X ),
				Math.Min( StartPoint.Y, EndPoint.Y )
			) );
			
			ActiveFileSaved = false;
			propertyGrid1.Refresh();
		}

		private void addFrameIdleSequenceToolStripMenuItem_Click( object sender, EventArgs e ) {
			Types.SpriteCfg cfg = (Types.SpriteCfg)propertyGrid1.SelectedObject;

			foreach(Types.SpriteSequenceCfg item in cfg.Sequences) {
				if( item.Name == "Idle" ) {
					MessageBox.Show( "An 'Idle' sequence already exsits!", "Error" );
					return;
				}
			}

			cfg.Frames.Add( new Vector2(
				Math.Min( StartPoint.X, EndPoint.X ),
				Math.Min( StartPoint.Y, EndPoint.Y )
			) );

			Types.SpriteSequenceCfg seq = new Types.SpriteSequenceCfg();
			seq.StartFrame = cfg.Sequences.Count;
			seq.EndFrame = cfg.Sequences.Count;
			cfg.Sequences.Add( seq );
			
			ActiveFileSaved = false;
			propertyGrid1.Refresh();
		}

		private void replaceFrameToolStripMenuItem_Click( object sender, EventArgs e ) {
			Types.SpriteCfg cfg = (Types.SpriteCfg)propertyGrid1.SelectedObject;

			cfg.Frames[(int)((ToolStripMenuItem)sender).Tag] = new Vector2(
				Math.Min( StartPoint.X, EndPoint.X ),
				Math.Min( StartPoint.Y, EndPoint.Y )
			);
			
			ActiveFileSaved = false;
			propertyGrid1.Refresh();
		}

		// ----------
		// PropertyGrid

		private void propertyGrid1_PropertyValueChanged( object sender, PropertyValueChangedEventArgs e ) {
			ActiveFileSaved = false;

			if( e.ChangedItem.Label != "TextureName" && e.ChangedItem.Label != "MaskTextureName" )
				return;

			AssetPathHandler handler = null;
			foreach(Attribute attr in e.ChangedItem.PropertyDescriptor.Attributes) {
				if( attr is AssetPathHandlerAttribute ) {
					handler = (AssetPathHandler)Activator.CreateInstance( ((AssetPathHandlerAttribute)attr).HandlerType );
					break;
				}
			}

			string finalValue = (string)e.ChangedItem.Value;
			if( handler != null )
				finalValue = handler.DesanitizeAssetPath( finalValue );

			Image asset = null;
			foreach(string ext in Globals.Extensions.Keys) {
				try {
					asset = Image.FromFile( Globals.AssetsPath + finalValue + ext );
					break;
				} catch {}
			}

			if( e.ChangedItem.Label == "TextureName" )
				CurrentAsset = asset;
			else
				CurrentMaskAsset = asset;

			HandleResize();
			pbCanvas.Refresh();
		}

		// ----------
		// My stuff

		private void HandleResize() {
			int w = pnlCanvasHolder.Width;
			int h = pnlCanvasHolder.Height;

			if( CurrentAsset != null ) {
				if( w < CurrentAsset.Width * Zoom )
					w = CurrentAsset.Width * Zoom;
				if( h < CurrentAsset.Height * Zoom )
					h = CurrentAsset.Height * Zoom;
			}

			pbCanvas.Width = w;
			pbCanvas.Height = h;
		}

		private GridItemCollection GetAllGridEntries( PropertyGrid grid ) {
			if (grid == null)
				throw new ArgumentNullException("grid");

			object view = grid.GetType().GetField("gridView", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(grid);
			return (GridItemCollection)view.GetType().InvokeMember("GetAllGridEntries", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, view, null);
		}

		private int Clamp( int value, int min, int max ) {
			return (value < min ? min : (value > max ? max : value));
		}

		// ----------
		// Options

		private void txtAssetsPath_TextChanged( object sender, EventArgs e ) {
			Globals.AssetsPath = txtAssetsPath.Text;
			try {
				Globals.AssetsPath = Path.GetFullPath( Globals.AssetsPath );
			} catch {}
		}

		private void cmdBrowse_Click( object sender, EventArgs e ) {
			FolderBrowserDialog fbd = new FolderBrowserDialog();
			fbd.Description = "Select the assets project folder.";

			if( fbd.ShowDialog() == DialogResult.OK && fbd.SelectedPath != null && fbd.SelectedPath.Length > 0 ) {
				try {
					fbd.SelectedPath = Path.GetFullPath( fbd.SelectedPath );
				} catch {}

				Globals.AssetsPath = fbd.SelectedPath;
				txtAssetsPath.Text = fbd.SelectedPath;
			}
		}

		private void nudSelStart_ValueChanged( object sender, EventArgs e ) {
			Globals.StartSnapSize = (int)nudSelStart.Value;
		}

		private void nudSelExpand_ValueChanged( object sender, EventArgs e ) {
			Globals.ExpandSnapSize = (int)nudSelExpand.Value;
		}
	}
}
